#!/usr/bin/env python
# Copyright(c) 2010 Nuttachat Wisittipanit. All rights reserved.

#from mahbo.information.database.utility.dbinterface import DatabaseInterface

from minings import (SVMpm,)

from xlwt import easyxf
from copy import deepcopy
import xlwt,interval,numpy


class FeatureReport(object):
    
    def __init__(self,**kwargs):
        #Process only one datasetname at a time      
        self.output_file    = ''
        self.pthreshold     = 0.05 #For Metastats
        #self.dset  -> {'gutmtpslhpcr_Colon_Lumen__Crohn_Colon__Crohn_Lumen': RESULTS isstance, ..}
        self.dset           = {}
        #self.dsort -> List of datasetname -> ['gutmtpslhpcr_Colon_Lumen__Crohn_Colon__Crohn_Lumen', ..] 
        self.dsort          = []
        self.nameabr        = []
        self.__dict__.update(kwargs)
        
    def xcelRecord(self):
        #Excel properties
        self.book           = xlwt.Workbook()
        self.xcel_col_width = 6000
        for i in range(len(self.dsort)):
            dname           = self.dsort[i]
            #subname -> 'Crohn_Colon__Crohn_Lumen'
            subname         = '__'.join(dname.split('__')[1:])
            nameAbr         = self.nameabr[i]
            #result_obj -> RESULTS instance
            result_obj      = self.dset[dname]
            results_svm     = result_obj.results_svm
            results_mstat   = result_obj.results_mstat
            if (results_mstat is None) or (results_svm is None) : 
                continue
            mstat_data      = results_mstat.orgnresult # MSTAT Result of orginal dataset (datafact.orgnRes.data)
            for j in results_svm.results:
                if j.SVMdrtn in (SVMpm.Drtn.B2UP,SVMpm.Drtn.T2DW,):
                    svm_data = j
                    break 
            gt              = Gather(mstat_data         = mstat_data        ,
                                     svm_data           = svm_data          ,
                                     mstat_pthreshold   = self.pthreshold   ,
                                     )                                       
            #########################                
            sheet               = self.book.add_sheet(nameAbr) # Add sheet to xcel files
            sheet.col(0).width  = self.xcel_col_width          # Adjust the width of the column
            sheet.row(0).write(0    ,dname      ,easyxf('font: bold True;'))
            sheet.row(1).write(0    ,'Positive' ,easyxf('font: bold True;'))
            sheet.row(2).write(0    ,'Negative' ,easyxf('font: bold True;'))
            self.cur_col    = 1                
            self.cur_row    = 1
            sheet.col(self.cur_col).width   =   self.xcel_col_width      
            #Put Head name positive and negative
            xname           = subname.split('__') #['Crohn_Colon','Crohn_Lumen']
            if 'Healthy Control' in xname:
                Positive    = xname[0] if xname[0] != 'Healthy Control' else xname[1]
                Negative    = xname[1] if xname[1] == 'Healthy Control' else xname[0]
            else:
                Positive    = xname[0]
                Negative    = xname[1]
            sheet.row(self.row_augment()).write(self.cur_col    ,Positive   ,easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col    ,Negative   ,easyxf('font: bold True;'))
            self.write_features(gt,sheet,'Relief Features'          ,gt.relief_ft       ,Positive   ,Negative   )
            self.write_features(gt,sheet,'SVM Features'             ,gt.svm_ft          ,Positive   ,Negative   )                     
            self.write_features(gt,sheet,'MSTAT Features'           ,gt.mstat_ft        ,Positive   ,Negative   )
            self.write_features(gt,sheet,'Relief and MSTAT'         ,gt.relief_mstat_ft ,Positive   ,Negative   )
            self.write_features(gt,sheet,'SVM and MSTAT Features'   ,gt.svm_mstat_ft    ,Positive   ,Negative   )
            #Put Fisher Exact Test
            self.cur_row    =   1
            self.col_augment()
            sheet.col(self.cur_col).width  = self.xcel_col_width
            sheet.row(self.row_augment()).write(self.col_augment()  ,'Fisher Exact Test',easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col-1      ,'p-value'          ,easyxf('font: bold True;'))
            self.cur_row    =   1
            sheet.col(self.cur_col).width  = self.xcel_col_width
            sheet.row(self.row_augment()).write(self.col_augment()  ,'Student t-test'   ,easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col-1      ,'Positive'         ,easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col-1      ,'Mean|STD|p-value' ,easyxf('font: bold True;'))
            self.cur_row    =   1
            sheet.col(self.cur_col).width  = self.xcel_col_width
            sheet.row(self.row_augment()).write(self.col_augment()  ,'Student t-test'   ,easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col-1      ,'Negative'         ,easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col-1      ,'Mean|STD'         ,easyxf('font: bold True;'))
            self.cur_row    =   1
            sheet.col(self.cur_col).width  = self.xcel_col_width
            sheet.row(self.row_augment()).write(self.col_augment()  ,'Student t-test'   ,easyxf('font: bold True;'))
            sheet.row(self.row_augment()).write(self.cur_col-1      ,None   )
            sheet.row(self.row_augment()).write(self.cur_col-1      ,'% Mean Difference|High'   ,easyxf('font: bold True;'))                            
        if len(self.dset) != 0:
            self.book.save(self.output_file) 
            
    def write_features(self,gather,sheet,name,features,pos = None,neg = None):
        #name -> 'Relief Features' or 'SVM Features'
        sheet.row(self.row_augment()).write(self.cur_col,name,easyxf('font: bold True;'))                
        for i in range(len(features)):
            #First column feature
            sheet.row(self.row_augment()).write(self.cur_col,features[i])
            if (pos is not None) and (neg is not None): 
                #Write Fisher p-value
                sheet.row(self.cur_row-1).write(self.cur_col+1,'%.4f' % gather.mstat_ft_hash[features[i]]) 
                pvalue  = gather.t_ft_hash[features[i]] #pvalue -> p-value of t-test
                b       = gather.t_ft_info[features[i]] #b      -> ( t1,{class1:(xbar,var),class2:(xbar,var)} )
                bpos    = '%.4f|%.4f|%.4f' % (b[1][pos][0],b[1][pos][1],pvalue)
                bneg    = '%.4f|%.4f' % (b[1][neg][0],b[1][neg][1])
                sheet.row(self.cur_row-1).write(self.cur_col+2,bpos) #Write Mean|STD|p-value (Positive)
                sheet.row(self.cur_row-1).write(self.cur_col+3,bneg) #Write Mean|STD|p-value (Negative)
                #Write mean difference
                md      = gather.md[features[i]]
                mdsort  = gather.md_sort[features[i]] #[(class1,xbar1),(class2,xbar2)]
                mdhigh  = 'Positive' if mdsort[0][0] == pos else 'Negative' 
                if   numpy.isnan(md):
                    mdx = 'Allzero'
                elif numpy.isinf(md):
                    mdx = '%s%5s%-10s' % ('Inf','|',mdhigh)
                else:
                    mdx = '%.2f%%%5s%-10s' % (md,'|',mdhigh)
                sheet.row(self.cur_row-1).write(self.cur_col+4,mdx) #Write Mean|STD|p-value (Negative)
                
    def row_augment(self):
        self.cur_row += 1
        return self.cur_row - 1
    
    def col_augment(self):
        self.cur_col += 1
        return self.cur_col - 1
    
    
class Gather(object):
    
    def __init__(self,**kwargs):
        self.mstat_data             = None
        self.svm_data               = None
        self.mstat_pthreshold       = 0.05
        self.__dict__.update(kwargs)
        if (self.mstat_data != None) and (self.svm_data != None):
            self.relief_ft              = sorted(self.svm_data.fullattsName) #List of Relief features
            self.relief_ft_max          = len(self.relief_ft) #Number of Relief features
            self.relief_ft_set          = set(self.relief_ft) #Set of Relief features
            self.svm_ft                 = sorted(self.svm_data.SVMbestattsName) #List of SVM Best features
            self.svm_ft_max             = len(self.svm_ft) #Number of SVM Best features
            self.svm_ft_set             = set(self.svm_ft) #Set of SVM Best features
            self.mstat_ft               = [] #[feature1,feature2, ..] MSTAT features having pvalue <= self.mstat_pthreshold
            self.mstat_ft_p             = [] #['feature1|p1','feature2|p2', ..] MSTAT features used in excel sheet
            self.mstat_ft_hash          = self.mstat_data.MSTATp_fisher #{feature1:p1,feature2:p2, ..}
            self.mstat_pselect          = [u for u in self.mstat_data.MSTATp_sort_fisher if u[1] in interval.Interval(0,self.mstat_pthreshold,lower_closed = True,upper_closed = True)] \
                                           if self.mstat_data.MSTATp_sort_fisher != None else [] #[(feature1,p1),(feature2,p2), ..] sorted from low-high
            for i in self.mstat_pselect:
                self.mstat_ft.append(i[0])
                self.mstat_ft_p.append('%s|%.4f' % (i[0],i[1]))
            self.mstat_ft.sort() #Sort MSTAT features
            self.mstat_ft_max           = len(self.mstat_ft) #Number of MSTAT features
            self.mstat_ft_set           = set(self.mstat_ft) #Set of MSTAT features
            self.relief_mstat_ft_set    = self.relief_ft_set & self.mstat_ft_set #Set of Mutual features between Relief and MSTAT
            self.relief_mstat_ft        = list(self.relief_mstat_ft_set) #List of Mutual features between Relief and MSTAT
            self.relief_mstat_ft.sort() #Sorted List of Mutual features between Relief and MSTAT
            self.relief_mstat_ft_max    = len(self.relief_mstat_ft) #Number of Mutual features between Relief and MSTAT
            self.relief_mstat_ft_p      = [] #Mutual features between Relief and MSTAT wit pvalues used in excel sheet
            for i in self.relief_mstat_ft:
                self.relief_mstat_ft_p.append('%s|%.4f' % (i,self.mstat_ft_hash[i]))
            self.svm_mstat_ft_set       = self.svm_ft_set & self.mstat_ft_set #Set of Mutual features between SVM and MSTAT
            self.svm_mstat_ft           = list(self.svm_mstat_ft_set) #List of Mutual features between SVM and MSTAT
            self.svm_mstat_ft.sort()
            self.svm_mstat_ft_max       = len(self.svm_mstat_ft) #Number of Mutual features between SVM and MSTAT
            self.svm_mstat_ft_p         = [] #Mutual features between SVM and MSTAT used in excel sheet
            for i in self.svm_mstat_ft:
                self.svm_mstat_ft_p.append('%s|%.4f' % (i,self.mstat_ft_hash[i]))
            #Student t-test information
            self.t_ft_hash  = self.mstat_data.MSTATp_tstat #{feature1:p1,feature2:p2 .. }
            self.t_ft_info  = self.mstat_data.MSTATinfo_tstat #{feature1:( t1,{class1:(xbar,var),class2:(xbar,var)} ) , .. } t1 is a t value
            #Find the mean difference
            self.md         = {} #{feature1:md,feature2:md .. }
            self.md_sort    = {} #{feature1:[(class1,xbar1),(class2,xbar2)], .. }
            self.md_hash    = {} #{feature1:xbar,feature2:xbar}, .. } Note: the highest xbar of 2 classes
            for i in self.t_ft_info:
                #i -> feature1
                v               = self.t_ft_info[i] 
                g               = v[1] #v[1] = {class1:(xbar1,var1),class2:(xbar2,var2)}
                #t_sort = [(class1,xbar1),(class2,xbar2)] Sorted from high to low based on xbar
                t_sort          = sorted([(u,g[u][0]) for u in g],lambda x,y: cmp(y[1],x[1])) 
                self.md_sort[i] = deepcopy(t_sort)
                for j in g:
                    #j       -> class1
                    #g[j]    -> (xbar1,var1)
                    #g[j][0] -> xbar1
                    self.md_hash[i] = g[j][0]
                xbar            = [u[0] for u in v[1].values()] #[xbar1,xbar2]
                #Find the mean difference
                low             = min(xbar)
                high            = max(xbar)
                md              = (((high-low)/float(low)) * 100 )
                self.md[i]      = md
                


    